#include "hash.h"
#include <string.h>
#include <ctype.h>

hash_t *hash_create() {
	int i;
	hash_t *table = (hash_t*) malloc(sizeof(hash_t));

	if (table == NULL) return NULL;
		
	table->used = 0;
	table->acessosParaEscrita=0;
	table->acessosParaLeitura=0;
	table->totalTentativasPalavrasEscritas=0;
	table->totalTentativasPalavrasLidas=0;

	for (i = 0; i < TAMANHOVETOR; i++)
		table->data[i] = CHECKMOD;

	return table;
}

void hash_reset(hash_t *table)
{
	int i;
		
	table->used = 0;
	table->acessosParaEscrita=0;
	table->acessosParaLeitura=0;
	table->totalTentativasPalavrasEscritas=0;
	table->totalTentativasPalavrasLidas=0;

	for (i = 0; i < TAMANHOVETOR; i++)
		table->data[i] = CHECKMOD;
}

void hash_stats(hash_t * table){
	printf("Tamanho da tabela %d, checkmod %d\n", TAMANHOVETOR, CHECKMOD);
	printf("Estatísticas de Uso Da Tabela\n");
	printf("Fator de carga %f\n", table->used*1.0f / TAMANHOVETOR);
	printf("Média de acessos por palavra buscada %f\n",table->acessosParaLeitura*1.0/table->totalTentativasPalavrasLidas);
	printf("Média de acessos por palavra escrita %f\n",table->acessosParaEscrita*1.0/table->totalTentativasPalavrasEscritas);
	printf("Total de colisões %d\n",table->acessosParaEscrita - table->totalTentativasPalavrasEscritas);
}

void hash_destroy(hash_t *table) {
	free(table);
}

void hash_insert(hash_t *table, char * palavra){

	unsigned long i,valorHash1,valorHash2,valorHash3;
	i=0;
	table->totalTentativasPalavrasEscritas++;
	valorHash1=hash1(palavra);
	valorHash3=hash3(palavra);


	if((table->data[valorHash1]==CHECKMOD)){
		table->data[valorHash1]=valorHash3;
		table->used++;
		table->acessosParaEscrita++;
		return;
	} else{
		valorHash2 = hash2(palavra);
		i = (valorHash1+valorHash2)% TAMANHOVETOR;
		while(i!=valorHash1){
			table->acessosParaEscrita++;

			if((table->data[i]==CHECKMOD)){
				table->data[i]=valorHash3;
				table->used++;
				break;
			}
			i=(i+valorHash2)%CHECKMOD;
		}
	}
}

int hash_find(hash_t *table, char * palavra){
	unsigned long i,valorHash1,valorHash2,valorHash3;
	table->totalTentativasPalavrasLidas++;
	i=0;
	valorHash1=hash1(palavra);
	valorHash3=hash3(palavra);

	if(table->data[valorHash1]==CHECKMOD){
		table->acessosParaLeitura++;
		return 0;
	}

	if( table->data[valorHash1]==valorHash3){
		table->acessosParaLeitura++;
		return 1;
	}

	else{
		valorHash2 = hash2(palavra);
		i = (valorHash1+valorHash2)% TAMANHOVETOR;
		while(i!=valorHash1){
			table->acessosParaLeitura++;

			if(table->data[i]==CHECKMOD){
				return 0;
			}
			if(table->data[i]==valorHash3){
				return 1;
			}
			i=(i+valorHash2)%CHECKMOD;
		}
	}
	return 0;

}

int  palavraToInt(unsigned char * palavra){
	int  total=0;
	int i;
	for(i=0;i<strlen(palavra);i++){
		total+=(tolower(palavra[i])*(i+1));
	}
	return total;
}
/*
unsigned long hash1(unsigned char * palavra){


	unsigned long total=palavraToInt(palavra);
	return total%TAMANHOVETOR;
}*/

unsigned long hash1(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

   while (c = *(str++))
        hash = (((hash << 5) + hash) + tolower(c))%TAMANHOVETOR; /* hash * 33 + c */

    return (hash);
}

int hash2(unsigned char * palavra){
	unsigned long long total=0;
	int i;
	for(i=0;i<strlen(palavra);i++)
		total+=(tolower(palavra[i])*(i+1000));
	total /= TAMANHOVETOR;
	total %= TAMANHOVETOR;
	return total > 0 ? total : 1;
}
/*int hash2(unsigned char * palavra){
	unsigned long long total=0;
	int i;
	for(i=0;i<strlen(palavra);i++)
		total+=(tolower(palavra[i])*(i+1));
	total /= TAMANHOVETOR;
	total %= TAMANHOVETOR;
	return total > 0 ? total : 1;
}
*/
/*
unsigned long hash3(unsigned char * palavra){
	unsigned long total = palavraToInt(palavra);
	total%=CHECKMOD;
	return total;
}*/

unsigned long hash3(unsigned char * str)
{
        unsigned long hash = 0;
        int c;

        while (c = *(str++))
            hash = (( tolower(c) + (hash << 6) + (hash << 16) - hash)%TAMANHOVETOR );

        return hash;
}
